package Thread.Thread_Security;


public class Demo23 {
    private static Object locker1=new Object();
    private static Object locker2=new Object();
    public static void main(String[] args) {
        //死锁第三个场景  n个线程n把锁
        //哲学家就餐问题
        /*死锁的四个必要条件：（缺一不可,少一个必要条件就不会形成死锁    ）
        1.锁是互斥的（一个线程拿到锁其他线程拿不到）锁的基本特性
        2.锁是不可被抢占的（线程1拿到锁a，如果线程1不主动释放锁，
        其他线程就不会拿到锁a）锁的基本特性
        3.请求和保持  线程1拿到锁a之后，不释放a的前提下，
        去拿锁b（自己代码结构问题），如果先释放a，再拿b，是不会有问题的
        4.循环等待（环路等待/循环依赖） 多个线程获取锁时候 存在循环等待（代码结构）
            如何避免循环等待：给锁编号，所有线程在加锁的时候，
            必须按照一定的顺序加锁（例如先加小编号再加大编号）
         3和4都是代码层面的，好调整，写代码时需要注意
         */
        Thread t1=new Thread(()->{
            //这里加锁的顺序是遵循先加小编号再加大编号
            synchronized (locker1){
                System.out.println("t1对locker1加锁完成");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (locker2){
                    System.out.println("t1对locker2加锁完成");
                }
            }
        });
        Thread t2=new Thread(()->{
            //更改此处党的加锁顺序，先加locker1在加锁locker2
            synchronized (locker1){
                System.out.println("t2对locker1加锁完成");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (locker2){
                    System.out.println("t2对locker2加锁完成");
                }
            }

        });

        //解决方案：1）避免锁嵌套
        //        2）约定加锁顺序
        t1.start();
        t2.start();
    }
}
